#pragma once

#include "DXUT.h"
#include "Index.h"
#include "Weight.h"

enum VERTEXTYPE
{
	VT_POS,
	VT_POSNORM,
	VT_POSNORMUV,
	VT_POSNORMUVTANG,
	VT_POSNORMUVTANG_SKIN
};

const unsigned int STRIDE_SIZE_ARRAY[] = {
	sizeof(D3DXVECTOR3),
	sizeof(D3DXVECTOR3)*2,
	sizeof(D3DXVECTOR3)*2 + sizeof(D3DXVECTOR2),
	sizeof(D3DXVECTOR3)*4 + sizeof(D3DXVECTOR2),
	sizeof(D3DXVECTOR3)*4 + sizeof(D3DXVECTOR2) + sizeof(D3DXVECTOR4)*2
};

const D3D11_INPUT_ELEMENT_DESC Vertex_layout[] =
{
	{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0,  0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};

const D3D11_INPUT_ELEMENT_DESC VertexNorm_layout[] =
{
	{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0,  0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	{ "NORMAL",   0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },	
};

const D3D11_INPUT_ELEMENT_DESC VertexNormUV_layout[] =
{
	{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0,  0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	{ "NORMAL",   0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,    0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};

const D3D11_INPUT_ELEMENT_DESC VertexNormUVTang_layout[] =
{
	{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0,  0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	{ "NORMAL",   0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,    0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	{ "TANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0, 32, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	{ "BINORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0, 44, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};

const D3D11_INPUT_ELEMENT_DESC VertexNormUVTangSkinned_layout[] =
{
	{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0,  0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	{ "NORMAL",   0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,    0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	{ "TANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0, 32, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	{ "BINORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0, 44, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	{ "BLENDINDICES", 0, DXGI_FORMAT_R32G32B32A32_FLOAT,    0, 56, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	{ "BLENDWEIGHT", 0, DXGI_FORMAT_R32G32B32A32_FLOAT,    0, 62, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};

const D3D11_INPUT_ELEMENT_DESC VertexNormUVTang_Morph_Layout[] =
{
	//1st Stream: Base Mesh
	{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0,  0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	{ "NORMAL",   0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,    0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	{ "TANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0, 32, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	{ "BINORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0, 44, D3D11_INPUT_PER_VERTEX_DATA, 0 },

	//2nd Stream:
	{"POSITION1", 0, DXGI_FORMAT_R32G32B32_FLOAT, 1,  0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	{ "NORMAL1",   0, DXGI_FORMAT_R32G32B32_FLOAT, 1, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },

	//3rd Stream:
	{"POSITION2", 0, DXGI_FORMAT_R32G32B32_FLOAT, 2,  0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	{ "NORMAL2",   0, DXGI_FORMAT_R32G32B32_FLOAT, 2, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },

	//4th Stream:
	{"POSITION3", 0, DXGI_FORMAT_R32G32B32_FLOAT, 3,  0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	{ "NORMAL3",   0, DXGI_FORMAT_R32G32B32_FLOAT, 3, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },

	//5th Stream:
	{"POSITION4", 0, DXGI_FORMAT_R32G32B32_FLOAT, 4,  0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	{ "NORMAL4",   0, DXGI_FORMAT_R32G32B32_FLOAT, 4, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },

};

class Vertex
{
public:
	//Components of a Vertex
	D3DXVECTOR3 Position;
	enum VERTEXTYPE m_iVType;
	const D3D11_INPUT_ELEMENT_DESC* layout;
	Vertex()
	{
		Position = D3DXVECTOR3(0,0,0);
		m_iVType = VT_POS;
		layout = Vertex_layout;	
	}
	virtual ~Vertex(){}
	//Constructor
	Vertex(const D3DXVECTOR3& Position)
	{
		m_iVType = VT_POS;
		this->Position = Position;
		layout = Vertex_layout;
	}
	unsigned int GetDataSize()
	{
		return STRIDE_SIZE_ARRAY[m_iVType];
	}
};


class VertexNorm: public Vertex
{
public:
	//Components of a Vertex
	D3DXVECTOR3 Normal;
	enum VERTEXTYPE m_iVType;
	VertexNorm():Vertex()
	{
		Normal = D3DXVECTOR3(0,0,0);
		m_iVType = VT_POSNORM;
		layout = VertexNorm_layout;
	}
	virtual ~VertexNorm(){}

	//Constructor
	VertexNorm(const D3DXVECTOR3& Position, const D3DXVECTOR3& Normal):Vertex(Position)
	{
		m_iVType = VT_POSNORM;
		this->Normal = Normal;
		layout = VertexNorm_layout;
	}
};


class VertexNormUV:public VertexNorm
{
public:
	//Components of a Vertex
	D3DXVECTOR2 UV;
	enum VERTEXTYPE m_iVType;
	VertexNormUV():VertexNorm()
	{
		UV = D3DXVECTOR2(0,0);
		m_iVType = VT_POSNORMUV;
		layout = VertexNormUV_layout;
	}
	virtual ~VertexNormUV(){}

	//Constructor
	VertexNormUV(const D3DXVECTOR3& Position, const D3DXVECTOR3& Normal, const D3DXVECTOR2& UV):VertexNorm(Position,Normal)
	{
		this->m_iVType = VT_POSNORMUV;
		this->UV = UV;
		this->layout = VertexNormUV_layout;
	}
};

class VertexNormUVTang: public VertexNormUV
{
public:
	//Components of a Vertex
	D3DXVECTOR3 Tangent;
	D3DXVECTOR3 BiNormal;
	enum VERTEXTYPE m_iVType;
	VertexNormUVTang():VertexNormUV()
	{
		Tangent = D3DXVECTOR3(0,0,0);
		BiNormal = D3DXVECTOR3(0,0,0);
		m_iVType = VT_POSNORMUVTANG;
		layout = VertexNormUVTang_layout;
	}
	virtual ~VertexNormUVTang(){}
	//Constructor
	VertexNormUVTang(const D3DXVECTOR3& Position, const D3DXVECTOR3& Normal, const D3DXVECTOR2& UV, const D3DXVECTOR3& Tangent, const D3DXVECTOR3& BiNormal):VertexNormUV(Position,Normal,UV)
	{
		this->m_iVType = VT_POSNORMUVTANG;
		this->Tangent = Tangent;
		this->BiNormal = BiNormal;
		this->layout = VertexNormUVTang_layout;
	}
};


class VertexNormUVTangSkinned: public VertexNormUVTang
{
public:
	SkinIndex BoneIndices;
	SkinWeight Weights;
	enum VERTEXTYPE m_iVType;
	//Constructor
	VertexNormUVTangSkinned():VertexNormUVTang()
	{
		m_iVType = VT_POSNORMUVTANG_SKIN;
		layout = VertexNormUVTangSkinned_layout;
	}
	VertexNormUVTangSkinned(const D3DXVECTOR3& Position, const D3DXVECTOR3& Normal, const D3DXVECTOR2& UV, const D3DXVECTOR3& Tangent, const D3DXVECTOR3& BiNormal, 
		const SkinIndex& BoneIndices, const SkinWeight& Weights):VertexNormUVTang(Position,Normal,UV, Tangent, BiNormal)
	{
		this->m_iVType = VT_POSNORMUVTANG_SKIN;
		this->BoneIndices = BoneIndices;
		this->Weights = Weights;
		this->layout = VertexNormUVTangSkinned_layout;
	}
};
